package notice

import (
	"fmt"
	"strings"

	"gitee.com/smewl13/beehive/pkg/lcrypto"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"gopkg.in/gomail.v2"
)

func NewMail(logger *zap.Logger, conf *viper.Viper) *Mail {
	port := conf.GetInt("mail.port")
	server := strings.TrimSpace(conf.GetString("mail.server"))
	user := strings.TrimSpace(conf.GetString("mail.user"))
	passwd := strings.TrimSpace(conf.GetString("mail.password"))
	encrypt := strings.TrimSpace(conf.GetString("mail.encrypt"))
	addrs := conf.GetStringSlice("mail.addrs")
	encrypt = strings.ToLower(encrypt)

	subject := strings.TrimSpace(conf.GetString("notice.subject"))
	if len(subject) == 0 {
		subject = "最新VPN连接信息"
	}

	var method lcrypto.Encrypter
	switch encrypt {
	case "sm4":
		key := conf.GetString("sm4.key")
		method = lcrypto.NewSM4(key)
	case "":
		method = nil
	default:
		logger.Fatal("[邮件通知]不支持的加密算法", zap.String("加密算法", encrypt))
	}

	if method != nil {
		buf, err := method.Decrypt([]byte(passwd))
		if err != nil {
			logger.Fatal(
				"[邮件通知]密码解密失败",
				zap.String("加密算法", encrypt),
				zap.String("密文密码", passwd),
				zap.Error(err),
			)
		}
		passwd = string(buf)
	}

	return &Mail{
		server:  server,
		port:    port,
		user:    user,
		passwd:  passwd,
		addrs:   addrs,
		subject: subject,
		logger:  logger,
	}
}

type Mail struct {
	status  bool
	port    int
	server  string
	user    string
	passwd  string
	subject string
	tpl     string
	addrs   []string
	logger  *zap.Logger
}

func (m *Mail) Name() string {
	return "mail"
}

func (m *Mail) Status() bool {
	return m.status
}

func (m *Mail) SetTpl(tpl string) {
	m.tpl = tpl
}

func (m *Mail) Send(data string) {
	m.status = false
	msg := gomail.NewMessage()
	msg.SetHeader("From", m.user)
	msg.SetHeader("To", m.addrs...)
	msg.SetHeader("Subject", m.subject)
	msg.SetBody("text/html", fmt.Sprintf(m.tpl, m.subject, data))
	conn := gomail.NewDialer(m.server, m.port, m.user, m.passwd)
	err := conn.DialAndSend(msg)
	if err != nil {
		m.logger.Error("[邮件通知]发送失败", zap.Error(err))
		return
	}
	m.status = true
	m.logger.Info("[邮件通知]发送成功")
}
